/*
 * Copyright @ 2018 - present 8x8, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.rtp.rtp.header_extensions

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.assertions.withClue
import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.ShouldSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import jakarta.xml.bind.DatatypeConverter.parseHexBinary

@SuppressFBWarnings(
    value = ["NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"],
    justification = "Use of pointer after shouldNotBeNull test."
)
class Av1DependencyDescriptorHeaderExtensionTest : ShouldSpec() {
    override fun isolationMode(): IsolationMode = IsolationMode.InstancePerLeaf

    /* Headers generated by Chrome 110 sending AV1 in its default configuration - L1T1 */
    val descL1T1 = parseHexBinary("80000180003a410180ef808680")

    val shortDesc = parseHexBinary("400001")

    val descL1T3 = parseHexBinary("800001800214eaa860414d141020842701df010d")

    /* Header generated by Chrome 112 sending AV1 with L3T3 set. */
    val descL3T3 = parseHexBinary(
        "d0013481e81485214eafffaaaa863cf0430c10c302afc0aaa0063c00430010c002a000a800060000" +
            "40001d954926e082b04a0941b820ac1282503157f974000ca864330e222222eca8655304224230ec" +
            "a87753013f00b3027f016704ff02cf"
    )

    val midDescScalable = parseHexBinary("d10146401c")

    val midDescScalable2 = parseHexBinary("c203ce581d30100000")
    val longForMid2 = parseHexBinary(
        "8003ca80081485214eaaaaa8000600004000100002aa80a8000600004000100002a000a8000600004" +
            "00016d549241b5524906d54923157e001974ca864330e222396eca8655304224390eca87753013f00b3027f016704ff02cf"
    )

    val descS3T3 = parseHexBinary(
        "c1000180081485214ea000a8000600004000100002a000a8000600004000100002a000a8000600004" +
            "0001d954926caa493655248c55fe5d00032a190cc38e58803b2a1954c10e10843b2a1dd4c01dc010803bc0218077c0434"
    )

    val descL3T3Key = parseHexBinary(
        "8f008581e81485214eaaaaa8000600004000100002aa80a8000600004000100002a000a80006000040" +
            "0016d549241b5524906d54923157e001974ca864330e222396eca8655304224390eca87753013f00b3027f016704ff02cf"
    )

    /* As of Chrome version 111, it doesn't support L3T3_KEY_SHIFT, but it does support L2T2_KEY_SHIFT, so test that. */
    val descL2T2KeyShift = parseHexBinary(
        "8700ed80e3061eaa82804028280514d14134518010a091889a09409fc059c13fc0b3c0"
    )

    /* The header Chrome 126 generates for VP8 keyframes when AV1 DD is enabled for VP8.  It has no chains. */
    val descNoChains = parseHexBinary(
        "8000138002044eaaaf2860414d34538a0940413fc0b3c0"
    )

    init {
        context("AV1 Dependency Descriptors") {
            context("a descriptor with a single-layer dependency structure") {
                val ld1r = Av1DependencyDescriptorReader(descL1T1, 0, descL1T1.size)
                val ld1 = ld1r.parse(null)
                should("be parsed properly") {
                    ld1.startOfFrame shouldBe true
                    ld1.endOfFrame shouldBe false
                    ld1.frameNumber shouldBe 0x0001

                    val structure = ld1.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 1
                    structure.maxTemporalId shouldBe 0
                    structure.maxSpatialId shouldBe 0
                }
                should("be parseable statelessly") {
                    val ld1s = ld1r.parseStateless()
                    ld1s.startOfFrame shouldBe true
                    ld1s.endOfFrame shouldBe false
                    ld1s.frameNumber shouldBe 0x0001

                    val structure = ld1s.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 1
                }
                should("calculate correct frame info") {
                    val ld1i = ld1.frameInfo
                    ld1i.spatialId shouldBe 0
                    ld1i.temporalId shouldBe 0
                }
                should("Calculate its own length properly") {
                    ld1.encodedLength shouldBe descL1T1.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(ld1.encodedLength)
                    ld1.write(buf, 0, buf.size)
                    buf shouldBe descL1T1
                }
            }
            context("a descriptor with a scalable dependency structure") {
                val ldsr = Av1DependencyDescriptorReader(descL3T3, 0, descL3T3.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe true
                    lds.frameNumber shouldBe 0x0134
                    lds.activeDecodeTargetsBitmask shouldBe 0x1ff

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 9
                    structure.maxTemporalId shouldBe 2
                    structure.maxSpatialId shouldBe 2
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    for (fromS in 0..2) {
                        for (fromT in 0..2) {
                            val fromDT = 3 * fromS + fromT
                            for (toS in 0..2) {
                                for (toT in 0..2) {
                                    val toDT = 3 * toS + toT
                                    /* With this structure you can switch down spatial layers, or to other temporal
                                     * layers within the same spatial layer, without a keyframe; but switching up
                                     * spatial layers needs a keyframe.
                                     */
                                    withClue("from DT $fromDT to DT $toDT") {
                                        if (fromS >= toS) {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe true
                                        } else {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe false
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b000000001
                    structure.getDtBitmaskForDt(1) shouldBe 0b000000011
                    structure.getDtBitmaskForDt(2) shouldBe 0b000000111
                    structure.getDtBitmaskForDt(3) shouldBe 0b000001001
                    structure.getDtBitmaskForDt(4) shouldBe 0b000011011
                    structure.getDtBitmaskForDt(5) shouldBe 0b000111111
                    structure.getDtBitmaskForDt(6) shouldBe 0b001001001
                    structure.getDtBitmaskForDt(7) shouldBe 0b011011011
                    structure.getDtBitmaskForDt(8) shouldBe 0b111111111
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descL3T3.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descL3T3
                }
            }
            context("a descriptor with a K-SVC dependency structure") {
                val ldsr = Av1DependencyDescriptorReader(descL3T3Key, 0, descL3T3Key.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe false
                    lds.frameNumber shouldBe 0x0085
                    lds.activeDecodeTargetsBitmask shouldBe 0x1ff

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 9
                    structure.maxTemporalId shouldBe 2
                    structure.maxSpatialId shouldBe 2
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    for (fromS in 0..2) {
                        for (fromT in 0..2) {
                            val fromDT = 3 * fromS + fromT
                            for (toS in 0..2) {
                                for (toT in 0..2) {
                                    val toDT = 3 * toS + toT
                                    /* With this structure you can switch to other temporal
                                     * layers within the same spatial layer, without a keyframe; but switching
                                     * spatial layers needs a keyframe.
                                     */
                                    withClue("from DT $fromDT to DT $toDT") {
                                        if (fromS == toS) {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe true
                                        } else {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe false
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b000000001
                    structure.getDtBitmaskForDt(1) shouldBe 0b000000011
                    structure.getDtBitmaskForDt(2) shouldBe 0b000000111
                    structure.getDtBitmaskForDt(3) shouldBe 0b000001000
                    structure.getDtBitmaskForDt(4) shouldBe 0b000011000
                    structure.getDtBitmaskForDt(5) shouldBe 0b000111000
                    structure.getDtBitmaskForDt(6) shouldBe 0b001000000
                    structure.getDtBitmaskForDt(7) shouldBe 0b011000000
                    structure.getDtBitmaskForDt(8) shouldBe 0b111000000
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descL3T3Key.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descL3T3Key
                }
            }
            context("a descriptor with a K-SVC dependency structure with key shift") {
                val ldsr = Av1DependencyDescriptorReader(descL2T2KeyShift, 0, descL2T2KeyShift.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe false
                    lds.frameNumber shouldBe 0x00ed
                    lds.activeDecodeTargetsBitmask shouldBe 0x0f

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 4
                    structure.maxTemporalId shouldBe 1
                    structure.maxSpatialId shouldBe 1
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    for (fromS in 0..1) {
                        for (fromT in 0..1) {
                            val fromDT = 2 * fromS + fromT
                            for (toS in 0..1) {
                                for (toT in 0..1) {
                                    val toDT = 2 * toS + toT
                                    /* With this structure you can switch to other temporal
                                     * layers within the same spatial layer, without a keyframe; but switching
                                     * spatial layers needs a keyframe.
                                     */
                                    withClue("from DT $fromDT to DT $toDT") {
                                        if (fromS == toS) {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe true
                                        } else {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe false
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b0001
                    structure.getDtBitmaskForDt(1) shouldBe 0b0011
                    structure.getDtBitmaskForDt(2) shouldBe 0b0100
                    structure.getDtBitmaskForDt(3) shouldBe 0b1100
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descL2T2KeyShift.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descL2T2KeyShift
                }
            }
            context("a descriptor following the dependency structure, specifying decode targets") {
                val ldsr = Av1DependencyDescriptorReader(descL3T3, 0, descL3T3.size)
                val lds = ldsr.parse(null)
                val mdsr = Av1DependencyDescriptorReader(midDescScalable, 0, midDescScalable.size)
                val mds = mdsr.parse(lds.newTemplateDependencyStructure)

                should("be parsed properly") {
                    mds.startOfFrame shouldBe true
                    mds.endOfFrame shouldBe true
                    mds.frameNumber shouldBe 0x0146

                    mds.newTemplateDependencyStructure shouldBe null
                    mds.activeDecodeTargetsBitmask shouldBe 0x7
                }
                should("calculate correct frame info") {
                    val mdsi = mds.frameInfo
                    mdsi.spatialId shouldBe 0
                    mdsi.temporalId shouldBe 1
                }
                should("Calculate its own length properly") {
                    mds.encodedLength shouldBe midDescScalable.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(mds.encodedLength)
                    mds.write(buf, 0, buf.size)
                    buf shouldBe midDescScalable
                }
            }
            context("another such descriptor") {
                val ldsr = Av1DependencyDescriptorReader(longForMid2, 0, longForMid2.size)
                val lds = ldsr.parse(null)
                val mdsr = Av1DependencyDescriptorReader(midDescScalable2, 0, midDescScalable2.size)
                val mds = mdsr.parse(lds.newTemplateDependencyStructure)

                should("be parsed properly") {
                    mds.startOfFrame shouldBe true
                    mds.endOfFrame shouldBe true
                    mds.frameNumber shouldBe 0x03ce

                    mds.newTemplateDependencyStructure shouldBe null
                    mds.activeDecodeTargetsBitmask shouldBe 0x7
                }
                should("calculate correct frame info") {
                    val mdsi = mds.frameInfo
                    mdsi.spatialId shouldBe 0
                    mdsi.temporalId shouldBe 1
                }
                should("Calculate its own length properly") {
                    mds.encodedLength shouldBe midDescScalable2.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(mds.encodedLength)
                    mds.write(buf, 0, buf.size)
                    buf shouldBe midDescScalable2
                }
            }
            context("a descriptor without a dependency structure") {
                val mdsr = Av1DependencyDescriptorReader(midDescScalable, 0, midDescScalable.size)
                should("be parseable as the stateless subset") {
                    val mds = mdsr.parseStateless()

                    mds.startOfFrame shouldBe true
                    mds.endOfFrame shouldBe true
                    mds.frameNumber shouldBe 0x0146

                    mds.newTemplateDependencyStructure shouldBe null
                }
                should("fail to parse if the dependency structure is not present") {
                    shouldThrow<Av1DependencyException> {
                        mdsr.parse(null)
                    }
                }
            }
            context("a descriptor without extended fields") {
                val ld1r = Av1DependencyDescriptorReader(descL1T1, 0, descL1T1.size)
                val ld1 = ld1r.parse(null)
                val sd1r = Av1DependencyDescriptorReader(shortDesc, 0, shortDesc.size)
                val sd1 = sd1r.parse(ld1.newTemplateDependencyStructure)

                should("be parsed properly") {
                    sd1.startOfFrame shouldBe false
                    sd1.endOfFrame shouldBe true
                    sd1.frameNumber shouldBe 0x0001

                    sd1.newTemplateDependencyStructure shouldBe null
                    sd1.activeDecodeTargetsBitmask shouldBe null
                }
                should("calculate correct frame info") {
                    val sd1i = sd1.frameInfo
                    sd1i.spatialId shouldBe 0
                    sd1i.temporalId shouldBe 0
                }
                should("Calculate its own length properly") {
                    sd1.encodedLength shouldBe shortDesc.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(sd1.encodedLength)
                    sd1.write(buf, 0, buf.size)
                    buf shouldBe shortDesc
                }
            }
            context("A descriptor with a Temporal-only scalability structure ") {
                val ldsr = Av1DependencyDescriptorReader(descL1T3, 0, descL1T3.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe false
                    lds.frameNumber shouldBe 0x0001
                    lds.activeDecodeTargetsBitmask shouldBe 0x7

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 3
                    structure.maxTemporalId shouldBe 2
                    structure.maxSpatialId shouldBe 0
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    val fromS = 0
                    for (fromT in 0..2) {
                        val fromDT = 3 * fromS + fromT
                        val toS = 0
                        for (toT in 0..2) {
                            val toDT = 3 * toS + toT
                            /* With this structure you can switch down spatial layers, or to other temporal
                             * layers within the same spatial layer, without a keyframe; but switching up
                             * spatial layers needs a keyframe.
                             */
                            withClue("from DT $fromDT to DT $toDT") {
                                structure.canSwitchWithoutKeyframe(
                                    fromDt = fromDT,
                                    toDt = toDT
                                ) shouldBe true
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b001
                    structure.getDtBitmaskForDt(1) shouldBe 0b011
                    structure.getDtBitmaskForDt(2) shouldBe 0b111
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descL1T3.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descL1T3
                }
            }
            context("a descriptor with a simulcast dependency structure") {
                val ldsr = Av1DependencyDescriptorReader(descS3T3, 0, descS3T3.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe true
                    lds.frameNumber shouldBe 0x0001
                    lds.activeDecodeTargetsBitmask shouldBe 0x1ff

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 9
                    structure.maxTemporalId shouldBe 2
                    structure.maxSpatialId shouldBe 2
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    for (fromS in 0..2) {
                        for (fromT in 0..2) {
                            val fromDT = 3 * fromS + fromT
                            for (toS in 0..2) {
                                for (toT in 0..2) {
                                    val toDT = 3 * toS + toT
                                    /* With this structure you can switch to other temporal
                                     * layers within the same spatial layer, without a keyframe; but switching
                                     * spatial layers needs a keyframe.
                                     */
                                    withClue("from DT $fromDT to DT $toDT") {
                                        if (fromS == toS) {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe true
                                        } else {
                                            structure.canSwitchWithoutKeyframe(
                                                fromDt = fromDT,
                                                toDt = toDT
                                            ) shouldBe false
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b000000001
                    structure.getDtBitmaskForDt(1) shouldBe 0b000000011
                    structure.getDtBitmaskForDt(2) shouldBe 0b000000111
                    structure.getDtBitmaskForDt(3) shouldBe 0b000001000
                    structure.getDtBitmaskForDt(4) shouldBe 0b000011000
                    structure.getDtBitmaskForDt(5) shouldBe 0b000111000
                    structure.getDtBitmaskForDt(6) shouldBe 0b001000000
                    structure.getDtBitmaskForDt(7) shouldBe 0b011000000
                    structure.getDtBitmaskForDt(8) shouldBe 0b111000000
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descS3T3.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descS3T3
                }
            }
            context("A descriptor with no chains") {
                val ldsr = Av1DependencyDescriptorReader(descNoChains, 0, descNoChains.size)
                val lds = ldsr.parse(null)
                should("be parsed properly") {
                    lds.startOfFrame shouldBe true
                    lds.endOfFrame shouldBe false
                    lds.frameNumber shouldBe 0x0013
                    lds.activeDecodeTargetsBitmask shouldBe 0x7

                    val structure = lds.newTemplateDependencyStructure
                    structure shouldNotBe null
                    structure!!.decodeTargetCount shouldBe 3
                    structure.maxTemporalId shouldBe 2
                    structure.maxSpatialId shouldBe 0
                }
                should("calculate correct frame info") {
                    val ldsi = lds.frameInfo
                    ldsi.spatialId shouldBe 0
                    ldsi.temporalId shouldBe 0
                }
                should("calculate correctly whether layer switching needs keyframes") {
                    val structure = lds.newTemplateDependencyStructure!!
                    val fromS = 0
                    for (fromT in 0..2) {
                        val fromDT = 3 * fromS + fromT
                        val toS = 0
                        for (toT in 0..2) {
                            val toDT = 3 * toS + toT
                            /* With this structure you can switch down spatial layers, or to other temporal
                             * layers within the same spatial layer, without a keyframe; but switching up
                             * spatial layers needs a keyframe.
                             */
                            withClue("from DT $fromDT to DT $toDT") {
                                structure.canSwitchWithoutKeyframe(
                                    fromDt = fromDT,
                                    toDt = toDT
                                ) shouldBe true
                            }
                        }
                    }
                }
                should("calculate DTI bitmasks corresponding to a given DT") {
                    val structure = lds.newTemplateDependencyStructure!!
                    structure.getDtBitmaskForDt(0) shouldBe 0b001
                    structure.getDtBitmaskForDt(1) shouldBe 0b011
                    structure.getDtBitmaskForDt(2) shouldBe 0b111
                }
                should("Calculate its own length properly") {
                    lds.encodedLength shouldBe descNoChains.size
                }
                should("Be re-encoded to the same bytes") {
                    val buf = ByteArray(lds.encodedLength)
                    lds.write(buf, 0, buf.size)
                    buf shouldBe descNoChains
                }
            }
        }
    }
}
